
#ifndef __JPGPARSE_H__
#define __JPGPARSE_H__
#include "stdlib.h"
#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "stdbool.h"

typedef enum
{
    SOI = 0xD8,  // 文件头
    EOI = 0xD9,  // 文件尾
    SOF0 = 0xC0, // 帧开始
    SOF1 = 0xC1, // 帧开始
    DHT = 0xC4,  // 定义Huffman表
    SOS = 0xDA,  // 扫描开始行
    DQT = 0xDB,  // 定义量化表
    DRI = 0xDD,  // 定义重新开始间隔
    APP0 = 0xE0, // 定义交换格式和图像识别信息
    APPN = 0xE1, // 自定义内容 从E1 ~ EF
    COM = 0xFE,  // 注释

} jpg_type_e;

typedef struct
{
    uint8_t flag; // 标志位 固定为0xFF
    uint8_t type; // 类型 参考 jpg_type_e
} jpg_head_t;

typedef struct
{
    jpg_head_t head; // 头
    uint16_t length; // 数据长度,不包括头长度,但是包括长度自身及数据内容长度
    uint8_t *data;   // 数据内容
} jpg_segment_t;

typedef struct
{
    jpg_type_e type;
    int8_t (*cb)(uint8_t *data, uint32_t len);
} jpgFunc_t;

// --------------------------------------------------------------------------
// 名称      字节数     值                   说明
// --------------------------------------------------------------------------
// 段标识       1         FF
// 段类型       1         E0
// 段长度       2         0010                    如果有RGB缩略图就＝16＋3n
// 　　（以下为段内容）
// 交换格式      5         4A46494600          “JFIF”的ASCII码
// 主版本号      1
// 次版本号      1
// 密度单位      1         0＝无单位；1＝点数/英寸；2＝点数/厘米
// X像素密度     2                             水平方向的密度
// Y像素密度     2                             垂直方向的密度
// 缩略图X像素  1                           缩略图水平像素数目
// 缩略图Y像素  1                           缩略图垂直像素数目
// （如果“缩略图X像素”和“缩略图Y像素”的值均＞0，那么才有下面的数据）
// RGB缩略图  3×n         n＝缩略图像素总数＝缩略图X像素×缩略图Y像素
// --------------------------------------------------------------------------

typedef struct
{
    uint8_t format[5];  // 交换格式
    uint8_t major;      // 主版本号
    uint8_t minor;      // 次版本号
    uint8_t unit;       // 密度单位
    uint16_t xdensity;  // X像素密度
    uint16_t ydensity;  // Y像素密度
    uint8_t xthumb;     // 缩略图X像素
    uint8_t ythumb;     // 缩略图Y像素
    uint8_t *thumbData; // 缩略图数据

} jpg_APP0_t;

// --------------------------------------------------------------------------
// 名称  字节数 值       说明
// --------------------------------------------------------------------------
// 段标识   1     FF
// 段类型   1     DB
// 段长度   2     43      其值＝3＋n（当只有一个QT时）
// （以下为段内容）
// QT信息  1     0－3位：QT号
// 4－7位：QT精度（0＝8bit，1字节；否则＝16bit，2字节）
// QT        n             n＝64×QT精度的字节数
// --------------------------------------------------------------------------

typedef struct
{
    union
    {
        uint8_t qtType;   // QT类型 0＝Luminance；1＝Chrominance
        uint8_t qtNumber; // QT号
    } qtInfo;

    uint8_t *qtPrecision; // QT精度量化表
} jpg_DQT_t;

// --------------------------------------------------------------------------
// 名称  字节数 值       说明
// --------------------------------------------------------------------------
// 段标识   1     FF
// 段类型   1     C0
// 段长度   2             其值＝8＋组件数量×3
// 　　（以下为段内容）
// 样本精度 1      8       每个样本位数（大多数软件不支持12和16）
// 图片高度 2
// 图片宽度 2
// 组件数量 1      3       1＝灰度图，3＝YCbCr/YIQ 彩色图，4＝CMYK 彩色图
// 　　（以下每个组件占用３字节）
// 组件 ID     1             1＝Y, 2＝Cb, 3＝Cr, 4＝I, 5＝Q
// 采样系数 1              0－3位：垂直采样系数
//                         4－7位：水平采样系数
// 量化表号 1
// ---------------------------------------------------------------------------

typedef struct
{
    uint8_t precision;   // 样本精度
    uint16_t height;     // 图片高度
    uint16_t width;      // 图片宽度
    uint8_t component;   // 组件数量
    uint8_t componentId; // 组件ID
    union
    {
        uint8_t hSample : 4; // 水平采样系数
        uint8_t vSample : 4; // 垂直采样系数
    } sample;
    uint8_t qtNumber; // 量化表号

} jpg_SOF0_t;

// 解析jpg文件
int8_t jpg_SOI(uint8_t *data, uint32_t len);
int8_t jpg_EOI(uint8_t *data, uint32_t len);
int8_t jpg_SOF0(uint8_t *data, uint32_t len);
int8_t jpg_SOF1(uint8_t *data, uint32_t len);
int8_t jpg_DHT(uint8_t *data, uint32_t len);
int8_t jpg_SOS(uint8_t *data, uint32_t len);
int8_t jpg_DQT(uint8_t *data, uint32_t len);
int8_t jpg_DRI(uint8_t *data, uint32_t len);
int8_t jpg_APP0(uint8_t *data, uint32_t len);
int8_t jpg_APPN(uint8_t *data, uint32_t len);
int8_t jpg_COM(uint8_t *data, uint32_t len);
int8_t jpgParse(uint8_t *fileAddr);

#endif